#ifndef __M_EX_H__
#define __M_EX_H__
#include "../mqCommon/logger.hpp"
#include "../mqCommon/helper.hpp"
#include "../mqCommon/mq_msg.pb.h"
#include <iostream>
#include <memory>
#include <mutex>
#include <unordered_map>

namespace yqx{
    //交换机类
    struct Exchange{
        using ptr = std::shared_ptr<Exchange>;
        std::string _name;
        ExchangeType _type;
        bool _durable;
        bool _auto_delete;

        Exchange(const std::string& name = "", ExchangeType type = UNKNOWNTYPE, bool durable = false, bool auto_delete = true):
        _name(name), _type(type), _durable(durable), _auto_delete(auto_delete){}
    };
    //交换机数据持久化类
    class ExchangeMapper{
        public:
            ExchangeMapper(const std::string& dbfile):_sh(dbfile){
                std::string parentPath = FileHelper::getParentDirectory(dbfile);
                FileHelper::createDirectory(parentPath);
                assert(_sh.open());
                createTable();
            }
            //创建表
            void createTable(){
                #define CREATE_EXCHANGE_TABLE "create table if not exists exchange_table(name varchar(32) primary key, type int, durable int, auto_delete int);"
                bool ret = _sh.exec(CREATE_EXCHANGE_TABLE, nullptr, nullptr);
                if(ret == false){
                    LOG("创建交换机数据库表失败！");
                    abort();
                }
            }
            //删除表
            void removeTable(){
                #define DROP_EXCHANGE_TABLE "drop table if exists exchange_table;"
                bool ret = _sh.exec(DROP_EXCHANGE_TABLE, nullptr, nullptr);
                if(ret == false){
                    LOG("删除交换机数据库表失败！");
                    abort();
                }
            }
            //向表中加入一个交换机数据
            bool insert(Exchange::ptr& exchange){
                std::stringstream ss;
                ss << "insert into exchange_table values(";
                ss << "'" << exchange->_name << "', ";
                ss << exchange->_type << ", ";
                ss << exchange->_durable << ", ";
                ss << exchange->_auto_delete << ");";
                return _sh.exec(ss.str(), nullptr, nullptr);
            }
            //删除一个表中交换机数据
            bool remove(const std::string& name){
                std::stringstream ss;
                ss << "delete from exchange_table where name=";
                ss << "'" << name <<"';";
                return _sh.exec(ss.str(), nullptr, nullptr);
            }
            using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
            //获得表中所有交换机数据
            ExchangeMap recovery(){
                ExchangeMap res;
                std::string sql = "select name, type, durable, auto_delete from exchange_table;";
                _sh.exec(sql, selectCallback, &res);
                return res;
            }
        private:
            static int selectCallback(void* arg, int numcol, char** row, char** fields){
                ExchangeMap* res = (ExchangeMap*)arg;
                auto exp = std::make_shared<Exchange>();
                exp->_name = row[0];
                exp->_type = (yqx::ExchangeType)std::stoi(row[1]);
                exp->_durable = (bool)std::stoi(row[2]);
                exp->_auto_delete = (bool)std::stoi(row[3]);
                res->insert(std::make_pair(exp->_name, exp));
                return 0;

            }
        private:
            SqliteHelper _sh;
    };
    //交换机数据管理类
        class ExchangeManager{
            public:
                using ptr = std::shared_ptr<ExchangeManager>;
                ExchangeManager(const std::string &dbfile):_mapper(dbfile){
                    _exchanges = _mapper.recovery();
                }
                //声明（创建）交换机
                bool declareExchange(const std::string& name, ExchangeType type, bool durable, bool auto_delete){
                    bool res = true;
                    std::unique_lock<std::mutex> lock(_mtx);
                    auto it = _exchanges.find(name);
                    if(it != _exchanges.end())
                        return true;
                    auto exp = std::make_shared<Exchange>(name, type, durable, auto_delete);
                    if(durable)
                        res = _mapper.insert(exp);
                    _exchanges.insert(std::make_pair(name, exp));
                    return res;
                }
                //删除交换机
                bool deleteExchange(const std::string& name){
                    bool res = true;
                    std::unique_lock<std::mutex> lock(_mtx);
                    auto it = _exchanges.find(name);
                    if(it == _exchanges.end())
                        return true;
                    if(it->second->_durable) 
                        res = _mapper.remove(name);
                    _exchanges.erase(name);
                    return res;

                }
                //获取指定的交换机对象
                Exchange::ptr selectExchange(const std::string& name){
                    std::unique_lock<std::mutex> lock(_mtx);
                    auto it = _exchanges.find(name);
                    if(it == _exchanges.end())
                        return nullptr;
                    return it->second;

                }
                //判断交换机是否存在
                bool exists(const std::string& name){
                    std::unique_lock<std::mutex> lock(_mtx);
                    auto it = _exchanges.find(name);
                    if(it == _exchanges.end())
                        return false;
                    return true;
                }
                //清理所有交换机数据
                void clear(){
                    std::unique_lock<std::mutex> lock(_mtx);
                    _mapper.removeTable();
                    _exchanges.clear();
                }
            private:
                std::mutex _mtx;
                ExchangeMapper _mapper;
                ExchangeMapper::ExchangeMap _exchanges;
        };
}
#endif